#ifndef     __LOGGER_H_INCLUDED__
#define     __LOGGER_H_INCLUDED__

#include    <cstdio>
#include    <string>

#define     LOG_INIT(name, ...) Logger::Instance().Initialize(name, ##__VA_ARGS__)
#define     LOG_DEBUG(fmt, ...) Logger::Instance().Write(Logger::Debug, __FILE__, __LINE__, fmt, ##__VA_ARGS__)
#define     LOG_INFO(fmt, ...)  Logger::Instance().Write(Logger::Info, __FILE__, __LINE__, fmt, ##__VA_ARGS__)
#define     LOG_WARN(fmt, ...)  Logger::Instance().Write(Logger::Warning, __FILE__, __LINE__, fmt, ##__VA_ARGS__)
#define     LOG_ERR(fmt, ...)   Logger::Instance().Write(Logger::Error, __FILE__, __LINE__, fmt, ##__VA_ARGS__)

#define     ASSERT(expr, fmt, ...)  if (!(expr)) { LOG_ERR(fmt, ##__VA_ARGS__); return; }
#define     ASSERT_RET(expr, ret, fmt, ...) if (!(expr)) { LOG_ERR(fmt, ##__VA_ARGS__); return ret; }

/**
 * File based logger
 */
class Logger {
public:
    /** Log message level */
    enum Level {
        Error = 0,
        Warning,
        Info,
        Debug,
    };

public:
    Logger();
    ~Logger();

    /**
     * Get runtime singleton instance of log tool
     */
    static Logger & Instance();

    /**
     * Initailize logger
     *
     * \param name Prefix of this log file
     * \param root Path to store log files.
     * \param max_level Message filter by level.
     * \param capacity Max size in bytes per-file.
     */
    void Initialize(
        const std::string & name = "main",
        const std::string & root = "./logs",
        Level max_level = Level::Info,
        size_t capacity = 8 * 1024 * 1024);

    /**
     * Write log message
     * 
     * \param level Message level.
     * \param file __FILE__
     * \param line __LINE__
     * \param fmt Output message format
     * \param ... Arguments to generate message
     */
    void Write(
        Level level,
        const char * file,
        int line,
        const char * fmt,
        ...);

private:
    FILE * _file;
    char * _buf;
    std::string _name;
    std::string _path;
    size_t _capacity;
    size_t _writed;
    Level _allowed_max_level;
    int _last_day;
};

#endif//!   __LOGGER_H_INCLUDED__